package cn.maihe.elg.operation.institution.service;

import cn.maihe.elg.operation.institution.ZhtInstitutionService;
import cn.maihe.elg.operation.common.TradeContext;
import cn.maihe.elg.operation.model.dto.BaseResp;
import cn.maihe.elg.operation.model.dto.InnerBaseResp;
import cn.maihe.elg.operation.model.dto.institution.ApplyOrderReqDTO;
import cn.maihe.elg.operation.model.dto.institution.PushGuaranteeRespDTO;
import cn.maihe.elg.operation.model.enums.AttachmentFileType;
import cn.maihe.elg.operation.model.vo.guarantee.TemplateParamsVO;
import cn.maihe.elg.operation.model.vo.order.ApplyOrderDetailVO;
import cn.maihe.elg.operation.repository.entity.AcceptOrderInfoDO;
import cn.maihe.elg.operation.repository.entity.GuaranteeAttachmentInfoDO;
import cn.maihe.elg.operation.repository.entity.GuaranteeTemplateDO;
import cn.maihe.elg.operation.service.guarantee.GuaranteeTemplateService;
import cn.maihe.elg.operation.service.order.AcceptOrderInfoService;
import cn.maihe.elg.operation.service.order.ApplyOrderInfoService;
import cn.maihe.elg.operation.service.order.GuaranteeAttachmentInfoService;
import cn.maihe.elg.operation.supports.electronicseal.kt.KtConfig;
import cn.maihe.elg.operation.supports.electronicseal.kt.KtOFDService;
import cn.maihe.elg.operation.institution.BaseInstitutionOpenService;
import cn.maihe.elg.operation.supports.system.ElgResourceService;
import cn.maihe.elg.operation.utils.*;
import com.kinsec.SignatureInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.Date;
import java.util.concurrent.CompletableFuture;

/**
 * @Description 出函机构受理申请保函服务
 * @Author WJH
 * @Date 2021/04/25
 */
@Service
@Slf4j
public class ZhtApplyGuaranteeService extends BaseInstitutionOpenService<ApplyOrderReqDTO, BaseResp> {

    private KtOFDService ktOFDService;

    private KtConfig.SealInfo zhongTianSealInfo;
    private ElgResourceService resourceService;

    @Resource
    private ZhtInstitutionService zhTInstitutionService;
    @Resource
    private GuaranteeTemplateService guaranteeTemplateService;
    @Resource
    private ApplyOrderInfoService applyOrderInfoService;
    @Resource
    private AcceptOrderInfoService acceptOrderInfoService;

    @Resource
    private GuaranteeAttachmentInfoService attachmentInfoService;

    public ZhtApplyGuaranteeService(KtOFDService ktOFDService, KtConfig ktConfig, ElgResourceService resourceService) {
        this.ktOFDService = ktOFDService;
        this.zhongTianSealInfo = ktConfig.getSealInfoByKey(KtConfig.SealInstitution.zhongTian);
        this.resourceService = resourceService;
    }

    /**
     * 保函平台--[初审|尽调|待报价|待支付|已支付|待出函]-->[调用内部出函机构]-->出函机构的初审|尽调|待支付|已支付|待出函与保函平台一致
     * -->收集信息|调用电子签章-->成功
     *
     * @param context
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    protected BaseResp processBusiness(TradeContext<ApplyOrderReqDTO, BaseResp> context) {
        ApplyOrderReqDTO req = context.getReq();

        PushGuaranteeRespDTO pushGuaranteeRespDTO = new PushGuaranteeRespDTO();
        pushGuaranteeRespDTO.setAcceptOrderNo(req.getAcceptOrderNo());
        pushGuaranteeRespDTO.setApplyOrderId(req.getApplyOrderId());

        ApplyOrderDetailVO detailVO = applyOrderInfoService.getApplyOrderDetailById(req.getApplyOrderId());
        AcceptOrderInfoDO acceptOrderInfo = acceptOrderInfoService.getByAcceptOrderNo(req.getAcceptOrderNo());
        GuaranteeTemplateDO templateDO = guaranteeTemplateService.selectById(acceptOrderInfo.getTemplateId());

        Date guaranteeTime = Date.from(Instant.now());
        String guaranteeNo = IdGenerate.genGuaranteeNo();
        //异步调用电子签章 生成 电子保函，生成后异步通知&推送保函至保函平台
        //1. TODO 根据模板id及订单信息合成 电子保函
        Path guaranteeFile = genGuaranteeFile(req, detailVO, templateDO,guaranteeNo,guaranteeTime);

        // TODO 获取到账证明
        Path receiveAmtFile = getReceiveAmtFile(req);

        //异步电子签章 到账证明
        this.singleSeal(req, guaranteeFile, receiveAmtFile, templateDO,guaranteeNo,guaranteeTime);

        //同步返回 是否受理成功
        return new BaseResp();
    }

    /**
     * 更新 生成电子保函后的信息变更
     *
     * @param pushGuaranteeRespDTO
     */
    private void updateGuaranteeInfo(PushGuaranteeRespDTO pushGuaranteeRespDTO) {

    }


    private Path getReceiveAmtFile(ApplyOrderReqDTO req) {
        //TODO 后管上送保存在 附件中
        try {
            GuaranteeAttachmentInfoDO infoDO = attachmentInfoService.getTypeAttachmentByAcceptOrderNo(req.getAcceptOrderNo(), AttachmentFileType.TYPE_6);
            File file = resourceService.getFileByRelativePath(infoDO.getFilePath());
            if (file == null || !file.exists()) {
                log.warn("查无此后管上传到账证明,暂默认统一文件");
//                throw new RuntimeException("查无此后管上传到账证明");
                return resourceService.getTempTestFile().toPath();
            } else {
                return file.toPath();
            }
        } catch (Exception e) {
            throw e;
        }
    }

    private Path genGuaranteeFile(ApplyOrderReqDTO req, ApplyOrderDetailVO detailVO, GuaranteeTemplateDO templateDO,String guaranteeNo,Date guaranteeTime) {
        try {
            Path srcTemplatePath = guaranteeTemplateService.getTemplatePath(templateDO.getId());
            TemplateParamsVO vo = TemplateParamsVO.builder().institutionName(detailVO.getInstitutionName())
                    .institutionLegal(detailVO.getGuarantorLegalPerson()).institutionAddress(detailVO.getGuarantorAddress())
                    .institutionPhone(detailVO.getGuarantorPhone()).institutionPostcode(detailVO.getGuarantorPostcode())
                    .guaranteeCode(guaranteeNo).guaranteeTime(DateUtil.formateDate(guaranteeTime,"yyyy-MM-dd HH:mm:ss"))
                    .bidBond(StringUtil.toYuan(detailVO.getBidBond()))
                    .bidBondUpper(CurrencyUpperUtil.toCurrencyUpper(new BigDecimal(StringUtil.toYuan(detailVO.getBidBond()))))
                    .projectCode(detailVO.getProjectCode()).projectName(detailVO.getProjectName())
                    .sectionCode(detailVO.getSectionCode()).sectionName(detailVO.getSectionName())
                    .beneficiary(detailVO.getTenderer()).bidder(detailVO.getBidderName())
                    //投递文件截止日期
                    .bidOpenTime(DateUtil.formateDate(detailVO.getBidOpenTime(), "yyyy-MM-dd HH:mm"))
                    .verifyUrl(detailVO.getVerifyUrl())//TODO 配置在开函机构么
                    .build();
            Path targetGuaranteePathDocX = resourceService.buildOfdPath(detailVO.getAcceptOrderNo(), "模板合成电子保函原文件", "docx");
            Path targetGuaranteePathPdf = resourceService.buildOfdPath(detailVO.getAcceptOrderNo(), "未签章电子保函", "ofd");
            //模板{{}}合成电子保函.docX
            DocX2PdfUtil.fmtTemplateDocXByValues(srcTemplatePath, targetGuaranteePathDocX, vo);
            //电子保函模板docX转换ofd
            ktOFDService.convertOfficeToOFD(targetGuaranteePathDocX, targetGuaranteePathPdf);
            return targetGuaranteePathPdf;
        } catch (Exception e) {
            throw new RuntimeException("保函模板合成电子保函异常：" + e.getMessage(), e);
        }
    }

    /**
     * 异步
     *
     * @param guaranteeFile
     * @param receiveAmtFile
     */
    private void singleSeal(ApplyOrderReqDTO req, Path guaranteeFile, Path receiveAmtFile, GuaranteeTemplateDO template,String guaranteeNo,Date guaranteeTime) {
        CompletableFuture.runAsync(() -> {
            try {
                Path ofdWithAttachment = Paths.get(guaranteeFile.getParent().toFile().getAbsolutePath(), "未签章电子保函附到账证明.ofd");
                String attachmentTitle = "到账证明";
                boolean convertTF = ktOFDService.convertOfdWithAttachment(guaranteeFile.toFile().getAbsolutePath(), ofdWithAttachment.toFile().getAbsolutePath(),
                        attachmentTitle, resourceService.getFileType(receiveAmtFile), receiveAmtFile.toFile().getAbsolutePath());
                Assert.isTrue(convertTF, "保函pdf转换签章ofd文件失败");

                //模板盖章位置及页数设置
                SignatureInfo guaranteeFileSignatureInfo = new SignatureInfo(template.getSignPageNo(), zhongTianSealInfo.getSealId(), zhongTianSealInfo.getCertIndexPassWd(),
                        template.getSignHorizontal(), template.getSignVertical());

                Path saveGuaranteeFile = resourceService.buildOfdPath(req.getAcceptOrderNo(), "已签章电子保函", "ofd");
                boolean tf = ktOFDService.singleSeal(ofdWithAttachment.toFile().getAbsolutePath(), guaranteeFileSignatureInfo, saveGuaranteeFile.toFile().getAbsolutePath());


                PushGuaranteeRespDTO pushGuaranteeRespDTO = new PushGuaranteeRespDTO();
                pushGuaranteeRespDTO.setAcceptOrderNo(req.getAcceptOrderNo());
                pushGuaranteeRespDTO.setApplyOrderId(req.getApplyOrderId());
                pushGuaranteeRespDTO.setGuaranteeNo(guaranteeNo);
                pushGuaranteeRespDTO.setGuaranteeTime(guaranteeTime);

//                pushGuaranteeRespDTO.setAllFileOfdPath(Paths.get(saveAllOfdFile));
                pushGuaranteeRespDTO.setAllFileOfdPath(saveGuaranteeFile);
                pushGuaranteeRespDTO.setGuaranteeFile(saveGuaranteeFile);
                pushGuaranteeRespDTO.setReceiveAmtFile(receiveAmtFile);

                // TODO 通知状态
                if (tf) {
                    ElgLogger.info(log, log -> log.info("受理订单号[{}] => 电子签章成功", req.getAcceptOrderNo()));
                    //通知并推送保函
                    zhTInstitutionService.pushGuarantee(InnerBaseResp.success(pushGuaranteeRespDTO));
                    ElgLogger.info(log, log -> log.info("受理订单号[{}] => 电子签章成功，开函成功通知并推送保函完成", req.getAcceptOrderNo()));
                } else {
                    ElgLogger.info(log, log -> log.info("受理订单号[{}] => 电子签章失败", req.getAcceptOrderNo()));
                    //通知开函失败：不通知
                    zhTInstitutionService.pushGuarantee(InnerBaseResp.error(pushGuaranteeRespDTO));
                    ElgLogger.info(log, log -> log.info("受理订单号[{}] => 电子签章失败，开函失败通知完成", req.getAcceptOrderNo()));
                }
            } catch (Exception e) {
                ElgLogger.info(log, log -> log.info("受理订单号[{}] => 电子签章异常:{}", req.getAcceptOrderNo(), e.getMessage(), e));
                zhTInstitutionService.pushGuarantee(InnerBaseResp.exception(e.getMessage()));
                ElgLogger.info(log, log -> log.info("受理订单号[{}] => 电子签章异常，开函异常通知完成", req.getAcceptOrderNo()));
            }


        });
    }


}
